#include <iostream>
using namespace std;
#include <string>
#include <vector>
#include <list>
#include <set>
#include <algorithm>
#include <functional>

//函数对象，就是类重载了()
template <typename T>
class ShowElement
{
public:
        ShowElement()
        {
                n = 0;
        }
        void operator()(T &t)
        {
                cout<<t<<endl;
        }
        void printN()
        {
                n++;
                cout<<"n: "<<n<<endl;
        }
private:
        int n;
};

//函数模板
template <typename T>
void FuncShowElement1(T &t)
{
        cout<<t<<endl;
}

void FuncShowElement2(int &t)
{
        cout<<t<<" ";
}

//函数对象 定义:函数对象和普通函数的异同
void test1()
{
        int a = 10;
        ShowElement<int> showElement;
        showElement(a); //函数对象的()的执行 很像一个函数 //仿函数

        FuncShowElement1<int>(a); 
        FuncShowElement2(a);
}

//函数对象是属于类对象,能突破函数的概念，能保持调用状态
//函数对象的好处
//      for_each算法中，函数对象做函数参数
//      for_each算法中，对象当返回值
void test2()
{
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(3);
        v1.push_back(5);

        for_each(v1.begin(), v1.end(), ShowElement<int>()); //匿名函数对象 匿名仿函数

        for_each(v1.begin(), v1.end(), FuncShowElement2); //通过回调函数 谁使用for_each 谁去填写回调函数的入口地址

        ShowElement<int> show1;
        //1.for_each算法的 函数对象的传递 是元素值传递,而不是引用传递
        for_each(v1.begin(), v1.end(), show1); 
        show1.printN();
        
        cout<<"通过for_each算法的返回值看调用的次数"<<endl;
        show1 = for_each(v1.begin(), v1.end(), show1); 
        show1.printN();
}

template<typename T>
class IsDiv
{
public:
        IsDiv(const T &divisor)
        {
                this->divisor = divisor;
        }
        bool operator()(T &t)
        {
                return (t % divisor == 0);
        }
private:
        T divisor;
};

void test3()
{
        vector<int> v;
        for (int i = 10; i < 33; i++)
        {
                v.push_back(i);
        }
        //int a = 4;
        //IsDiv<int> myDIv(a);
        //find_if(v.begin(), v.end(), myDIv);
        vector<int>::iterator it = find_if(v.begin(), v.end(), IsDiv<int>(4));
        if(it == v.end()){
                cout<<"容器中没有被4整除的元素"<<endl;
        }else{
                cout<<"第一个被4整除的元素是:"<<*it<<endl;
        }
        //find_if返回的是迭代器
        //要点: 分清楚 stl算法返回值是迭代器 还是 谓词(函数对象) 是stl算法入门的重要点
}

template <typename T>
class SumAdd
{
public:
        T operator()(T t1, T t2)
        {
                return t1+t2;
        }
};

void test4()
{
        //v1容器的第一个元素 和v2容器的第三个元素进行比较
        vector<int> v1, v2;
        vector<int> v3;
        v1.push_back(1);
        v1.push_back(3);
        v1.push_back(5);

        v2.push_back(2);
        v2.push_back(4);
        v2.push_back(6);

        v3.resize(10);

        transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), SumAdd<int>());
        //transform 把运算结果的 迭代器的开始位置 返回出来

        for (vector<int>::iterator it = v3.begin(); it != v3.end(); it++)
        {
                cout<<*it<<endl;
        }
        
}

bool MyCompare(const int &a, const int &b)
{
        return a < b; //从小到大
}

void test5()
{
        vector<int> v1(10);
        for (int i = 0; i < 10; i++){
                int tmp = rand() % 100;
                v1[i] = tmp;
        }
        for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++)
        {
                cout<<*it<<" ";
        }
        cout<<endl;
        
        for_each(v1.begin(), v1.end(), FuncShowElement2);
        cout<<endl;

        sort(v1.begin(), v1.end(), MyCompare);
        for_each(v1.begin(), v1.end(), FuncShowElement2);
        cout<<endl;
}

struct CompareNoCase{
        bool operator()(const string &str1, const string &str2){
                string s1;
                s1.resize(str1.size());
                transform(str1.begin(), str1.end(), s1.begin(), ::tolower);

                string s2;
                s2.resize(str2.size());
                transform(str2.begin(), str2.end(), s2.begin(), ::tolower);
                
                return (s1 < s2); //从小到大
        }
};

void test6()
{
        set<string> set1;
        set1.insert("bbb");
        set1.insert("aaa");
        set1.insert("ccc");
        set<string>::iterator it = set1.find("aAa"); //find函数 默认 区分大小写的
        if(it != set1.end()){
                cout<<"查找到 aaa"<<endl;
        }else{
                cout<<"没有查找到 aaa"<<endl;
        }

        set<string, CompareNoCase> set2;
        set2.insert("bbb");
        set2.insert("aaa");
        set2.insert("ccc");

        set<string, CompareNoCase> ::iterator it2 = set2.find("aAa"); //find函数 默认 区分大小写的
        if(it2 != set2.end()){
                cout<<"查找到 aaa"<<endl;
        }else{
                cout<<"没有查找到 aaa"<<endl;
        }
}

int main(int argc, char const *argv[])
{
        //test1(); //函数对象的基本概念
        //test2();//函数对象的好处 函数对象做函数参数 函数对象做返回值
        //test3(); //一元谓词 函数对象是一个参数并返回bool 或者是 一个带一个参数的回调函数并返回bool
        //test4(); //二元谓词 函数对象是两个参数并返回bool 或者是 一个到两个参数的回调函数并返回bool
        //test5();//二元谓词 函数对象是两个参数并返回bool 或者是 一个到两个参数的回调函数并返回bool
        test6(); //二元谓词在set集合中的运用
        return 0;
}
